/*
   Window Properties.cs
   Created by Randall Maas, Saturday January 31 2009
   Copyright (c) 2009, Randall Maas
   All rights reserved.

   Redistribution and use in source and binary forms, with or without
   modification, are permitted provided that the following conditions are met:

   Redistributions of source code must retain the above copyright notice, this
   list of conditions and the following disclaimer.

   Redistributions in binary form must reproduce the above copyright notice,
   this list of conditions and the following disclaimer in the documentation
   and/or other materials provided with the distribution.

   Neither the name of Blackwood Designs, LLC nor the names of its contributors
   may be used to endorse or promote products derived from this software without
   specific prior written permission.

   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
   AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
   LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
   CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
   SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
   INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 
   CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
   ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
   THE POSSIBILITY OF SUCH DAMAGE.
*/

using System ;
using System . Runtime . InteropServices;
using System . Text;
using System . Diagnostics;

public static partial class Win32
{
   #region Window Title
   /// <summary>
   /// Gets the length of the window title
   /// </summary>
   /// <param name="Wnd">The window handle</param>
   /// <returns>0 on error, otherwise the length of the window title</returns>
   /// <seealso cref="http://pinvoke.net/default.aspx/user32/GetWindowTextLength.html" />
   [DllImport("user32.dll", SetLastError=true, CharSet=CharSet.Auto)]
   static extern int GetWindowTextLength(IntPtr Wnd);

   /// <summary>
   /// Used to get the title of the specified window
   /// </summary>
   /// <param name="Wnd">The window handle</param>
   /// <param name="lpString">The string buffer</param>
   /// <param name="nMaxCount">The maximum number of characters to transfer</param>
   /// <returns>The length of the string (excluding null)</returns>
   /// <seealso cref="http://pinvoke.net/default.aspx/user32/GetWindowText.html" />
   [DllImport("user32.dll", SetLastError = true, CharSet = CharSet.Unicode)]
   static extern int GetWindowText(IntPtr Wnd, [MarshalAs(UnmanagedType.LPWStr)][Out] StringBuilder lpString, UInt32 nMaxCount);

   /// <summary>
   /// Retrieves the title of the specified window
   /// </summary>
   /// <remarks>
   ///  This implicitly sends a bunch of windows messages to coordinate with the
   ///  specified window
   /// todo: consider falling back to : InternalGetWindowText 
   /// </remarks>
   /// <param name="Handle">The window handle</param>
   /// <returns>null on error, otherwise the title string</returns>
   internal static string Title(IntPtr Handle)
   {
      // Find out how much to allocate
      int Length       = GetWindowTextLength(Handle);
      if (Length < 1)
        return null;

      // Retrieve the title string
      StringBuilder SB = new StringBuilder(Length + 1);
      if (GetWindowText(Handle, SB, (uint) SB . Capacity) < 1)
        return null;
      return String . Intern(SB . ToString());
   }
   #endregion

   #region Window Thread & Process
   /// <summary>
   /// Retrieves the process identifier of the thread created the specified window.
   /// It provides process id as an option
   /// </summary>
   /// <param name="Wnd">The window of interest</param>
   /// <param name="lpdwProcessId">The process identifer</param>
   /// <returns>The thread identifier</returns>
   [DllImport("user32.dll", SetLastError = true)]
   static extern UInt32 GetWindowThreadProcessId(IntPtr Wnd, out UInt32 lpdwProcessId);

   /// <summary>
   /// Retrieves the process id for the specified window.
   /// </summary>
   /// <param name="Wnd">The window of interest</param>
   /// <param name="lpdwProcessId">The process identifer</param>
   /// <returns>The thread identifier</returns>
   [DllImport("user32.dll", SetLastError=true)]
   static extern UInt32 GetWindowThreadProcessId(IntPtr Wnd, IntPtr ProcessId);

   /// <summary>
   /// Retrieves the process for the given window
   /// </summary>
   /// <param name="Handle"></param>
   /// <returns></returns>
   internal static Process Process(IntPtr Handle)
   {
      uint ProcessId= 0;
      GetWindowThreadProcessId(Handle, out ProcessId);
      return System . Diagnostics . Process . GetProcessById((int) ProcessId);
   }


   /// <summary>
   /// Retrieves the address of the window procedure, or a handle representing
   /// the address of the window procedure. You must use the CallWindowProc
   /// function to call the window procedure.
   /// </summary>
   /// <param name="Win">The message queue to query</param>
   /// <returns>the address of the window procedure, or a handle representing
   /// the address of the window procedure.</returns>
   internal static IntPtr WinProcedure(IntPtr Win)
   {
      return GetWindowLongPtr(Win, GWL . WNDPROC);
   }


   /// <summary>
   /// Retrieves the user data associated with the window. This data is intended
   /// for use by the application that created the window. Its value is initially
   /// zero.
   /// </summary>
   /// <param name="Win"></param>
   /// <returns></returns>
   internal static IntPtr UserData(IntPtr Win)
   {
      return GetWindowLongPtr(Win, GWL . USERDATA);
   }

   /// <summary>
   /// The identifier of the window
   /// </summary>
   /// <param name="Win"></param>
   /// <returns>The windows identifier</returns>
   internal static IntPtr WinId(IntPtr Win)
   {
      return GetWindowLongPtr(Win, GWL . ID);
   }
   #endregion

   #region Window Position / Size
   /// <summary>
   /// Retrieves the bounding rectangle for the window
   /// </summary>
   /// <param name="Win">The window</param>
   /// <param name="lpRect"></param>
   /// <returns>true on success, false on error</returns>
   /// <seealso cref="http://msdn.microsoft.com/en-us/library/ms633519(VS.85).aspx"/>
   [DllImport("user32.dll")]
   [return : MarshalAs(UnmanagedType.Bool)]
   internal static extern bool GetWindowRect(IntPtr Win, out RECT lpRect);
   #endregion


#if false
   Not needed since this gets the name for the process and the process object's got it
   [DllImport("user32.dll")]
   static extern Int32 GetWindowModuleFileName(IntPtr Wnd, StringBuilder title, Int32 size);

   private string GetWindowModuleFileName(IntPtr Wnd)
   {
       uint processId = 0;
       const int nChars = 1024;
       StringBuilder filename = new StringBuilder(nChars);
       GetWindowThreadProcessId(Wnd, out processId);
       IntPtr hProcess = OpenProcess(1040, 0, processId);
       GetModuleFileNameEx(hProcess,IntPtr.Zero,filename,nChars);
       CloseHandle(hProcess);
       return (filename.ToString());
   }
#endif

   #region Long / LongPtr Properties
   /// <summary>
   /// </summary>
   /// <param name="hWnd"></param>
   /// <param name="Index"></param>
   /// <returns></returns>
   /// <remarks>
   /// This method is required because versions of Windows prior to Vista do
   /// not support GetWindowLongPtr (called GetWindowLongPtr64 here)
   /// </remarks>
   static IntPtr GetWindowLongPtr(IntPtr hWnd, GWL Index)
   {
      // If 64 bit mode, use the other procedure
      if (IntPtr.Size == 8)
        return GetWindowLongPtr64(hWnd, (int) Index);
      return new IntPtr(GetWindowLong(hWnd, (Int32) Index));
   }

   /// <summary>
   /// Fetches a property value by index
   /// </summary>
   /// <param name="Wnd">Window to get property about</param>
   /// <param name="nIndex">Property index</param>
   /// <returns>Property value</returns>
   [DllImport("user32.dll", EntryPoint = "GetWindowLongPtr")]
   static extern IntPtr GetWindowLongPtr64(IntPtr Wnd, int nIndex);


   /// <summary>
   /// Fetches a property value by index
   /// </summary>
   /// <param name="Wnd">Window to get property about</param>
   /// <param name="nIndex">Property index</param>
   /// <returns>Property value</returns>
   [DllImport("user32.dll", SetLastError = true)]
   internal static extern Int32 GetWindowLong(IntPtr Wnd, Int32 nIndex);
   #endregion



   #region Window Visibility
   /// <summary>
   /// 
   /// </summary>
   /// <param name="Wnd"></param>
   /// <returns></returns>
   [DllImport("user32.dll", EntryPoint="IsWindowVisible", ExactSpelling=false, CharSet=CharSet.Auto, SetLastError=true)]
   [return: MarshalAs(UnmanagedType.Bool)]
   internal static extern bool IsVisible(IntPtr hWnd);

   /// <summary>
   /// 
   /// </summary>
   /// <param name="Win"></param>
   /// <returns></returns>
   internal static bool IsTool(IntPtr Win)
   {
      return (GetWindowLong(Win, (int) GWL . EXSTYLE) & 0x00000080) > 0;
   }

/*
DWL_DLGPROC
Retrieves the address of the dialog box procedure, or a handle representing the address of the dialog box procedure. You must use the CallWindowProc function to call the dialog box procedure.
DWL_MSGRESULT
Retrieves the return value of a message processed in the dialog box procedure.
DWL_USER
Retrieves extra information private to the application, such as handles or pointers.
*/

   /// <summary>
   /// Indicates whether the window is maximized.
   /// </summary>
   /// <returns>true if the window is maximized, false otherwise</returns>
   internal static bool IsMaximized(IntPtr HWnd)
   {
      return 0 != (WS . MAXIMIZE & (WS) GetWindowLong(HWnd, (int) GWL . STYLE));
   }
   #endregion
}
